﻿using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace Odyssey.Consul.Implementations
{
    using Features;
    using Http;
    public abstract class BaseConsulAPI : IConsulAPI
    {
        private readonly string _apiVersion;

        public IHttpRequester HttpRequester { get; }

        public IConsulConfiguration ConsulConfiguration { get; }

        public EnumResource Resource { get; }


        public BaseConsulAPI(IHttpRequester httpRequester, IConsulConfiguration consulConfiguration, EnumResource enumResource)
        {
            HttpRequester = httpRequester;
            ConsulConfiguration = consulConfiguration;
            Resource = enumResource;
            _apiVersion = string.IsNullOrWhiteSpace(consulConfiguration.APIVersion) ? "v1" : consulConfiguration.APIVersion;
        }

        public async Task<TResult> ApiSend<TResult>(string path, EnumConsulHttpMethod enumConsulHttpMethod = EnumConsulHttpMethod.Get, QueryParameter queryParameter = null, IDictionary<string, string> requestHeaders = null)
        {
            return await HttpRequester.ConsulSendAsync<TResult>(BuildUri(path, queryParameter ?? QueryParameter.Default), enumConsulHttpMethod, requestHeaders);
        }

        public async Task<TResult> ApiSend<TArgument, TResult>(string path, TArgument argument, EnumConsulHttpMethod enumConsulHttpMethod = EnumConsulHttpMethod.Put, QueryParameter queryParameter = null, IDictionary<string, string> requestHeaders = null)
        {
            return await HttpRequester.ConsulSendAsync<TArgument, TResult>(BuildUri(path, queryParameter ?? QueryParameter.Default), argument, enumConsulHttpMethod, requestHeaders);
        }

        public async Task<string> ApiSendString(string path, EnumConsulHttpMethod enumConsulHttpMethod = EnumConsulHttpMethod.Delete, QueryParameter queryParameter = null, IDictionary<string, string> requestHeaders = null)
        {
            return await HttpRequester.ConsulSendAsync(BuildUri(path, queryParameter ?? QueryParameter.Default), enumConsulHttpMethod, requestHeaders);
        }


        public async Task<HttpResponseMessage> ApiSendResponse(string path, object data = null, EnumConsulHttpMethod enumConsulHttpMethod = EnumConsulHttpMethod.Post, QueryParameter queryParameter = null, IDictionary<string, string> requestHeaders = null)
        {
            return await HttpRequester.ConsulSendAsync(BuildUri(path, queryParameter ?? QueryParameter.Default), data, enumConsulHttpMethod, requestHeaders);
        }

        public async Task<HttpResponseMessage> ApiSendResponse(string path, byte[] data, EnumConsulHttpMethod enumConsulHttpMethod = EnumConsulHttpMethod.Post, QueryParameter queryParameter = null, IDictionary<string, string> requestHeaders = null)
        {
            return await HttpRequester.ConsulSendAsync(BuildUri(path, queryParameter ?? QueryParameter.Default), data, enumConsulHttpMethod, requestHeaders);
        }

        protected string BuildUri(string root, string action)
        {
            root = root.Trim('/');
            action = action.Trim('/');
            if (string.IsNullOrWhiteSpace(action))
            {
                return root;
            }
            return $"{root}/{action}";
        }

        protected string BuildUri(string path, QueryParameter queryParameter)
        {
            return $"{ConsulConfiguration.Host}/{_apiVersion}/{path}{queryParameter.ToString()}";
        }


        protected Dictionary<string, string> BuildTokenHeader()
        {
            return BuildTokenHeader(Resource);
        }

        protected Dictionary<string, string> BuildTokenHeader(string token)
        {
            return ConsulHeaders.BuildConsulToken(token);
        }

        protected Dictionary<string, string> BuildTokenHeader(EnumResource enumResource)
        {
            return BuildTokenHeader(new EnumResource[] { enumResource });
        }

        protected Dictionary<string, string> BuildTokenHeader(EnumResource[] enumResources)
        {
            var token = ConsulConfiguration.SecretID;
            foreach (var enumResource in enumResources)
            {
                var hasResourceToken = false;
                switch (enumResource)
                {
                    case EnumResource.Agent:
                        if (!string.IsNullOrWhiteSpace(ConsulConfiguration.AgentToken))
                        {
                            token = ConsulConfiguration.AgentToken;
                            hasResourceToken = true;
                        }
                        break;
                    case EnumResource.Node:
                        if (!string.IsNullOrWhiteSpace(ConsulConfiguration.NodeToken))
                        {
                            token = ConsulConfiguration.NodeToken;
                            hasResourceToken = true;
                        }
                        break;
                    case EnumResource.Service:
                        if (!string.IsNullOrWhiteSpace(ConsulConfiguration.ServiceToken))
                        {
                            token = ConsulConfiguration.ServiceToken;
                            hasResourceToken = true;
                        }
                        break;
                }
                if (hasResourceToken)
                {
                    break;
                }
            }
            return ConsulHeaders.BuildConsulToken(token);
        }
    }
}
